module cpld_uart_transmitter #(
parameter UART_FIFO_COUNTER_W = 5,
parameter UART_FIFO_WIDTH = 8)
(
input                                         clk,
input                                         rst_n,
input                                     uart_clk         ,
input                                     uart_rst_n       ,
input                                     luart_sol_sw,
input [7:0]                                 lcr,
input                                         tfifo_wren,
input [UART_FIFO_WIDTH-1:0]             tfifo_wrdata_in,
input                                         enable,
input                                         tx_reset,
input                                         remote_rfifo_full,
input                                         lsr_read_rise, //reset of fifo
output                                         serial_out,
output reg [2:0]                                 tstate,
//output [UART_FIFO_COUNTER_W-1:0]     tf_count,
output [UART_FIFO_WIDTH-1:0]             transmitter_data_out,
output                               transmitter_rden,
output                               tfifo_full,
output                               tfifo_empty
);


reg [4:0]                                     counter;
reg [2:0]                                     bit_counter;   // counts the bits to be sent
reg [6:0]                                     shift_out;    // output shift register
reg                                             stx_o_tmp;
reg                                             parity_xor;  // parity of the word
reg                                             serial_data_read;
reg                                             bit_out;

// TX FIFO instance
//
// Transmitter FIFO signals

wire                                             tf_overrun;
wire [UART_FIFO_COUNTER_W-1:0]         tf_count;
wire [UART_FIFO_WIDTH-1:0]             tf_data_out;
reg tfifo_rden;
always @(*) begin
   if(luart_sol_sw) tfifo_rden = transmitter_rden;
   else tfifo_rden = serial_data_read;
end
assign transmitter_rden = !remote_rfifo_full && !tfifo_empty&&luart_sol_sw;
//wire fifo_rst_n = rst_n | (!tx_reset);
uart_tfifo fifo_tx(    // error bit signal is not used in transmitter FIFO
    .clk(clk),
    .rst_n(rst_n),
    .data_in(tfifo_wrdata_in ),
    .data_out(tf_data_out),
    .wen(tfifo_wren),
    .ren(tfifo_rden),
    .overrun( ),
    .count(tf_count),
    .fifo_reset(tx_reset),
    .reset_status(lsr_read_rise),
    .full(tfifo_full),
    .empty(tfifo_empty)
);

//fifo_32x8 fifo_tx(
//.Data(tfifo_wrdata_in), 
//.WrClock(clk), 
//.RdClock(clk), 
//.WrEn(tfifo_wren),
//.RdEn(tfifo_rden), 
//.Reset(fifo_rst_n), 
//.RPReset(fifo_rst_n), 
//.Q(tf_data_out), 
//.Empty(tfifo_empty),
//.Full(tfifo_full), 
//.AlmostEmpty(AlmostEmpty), 
//.AlmostFull(AlmostFull)
// );


// TRANSMITTER FINAL STATE MACHINE

parameter IDLE_STATE        = 3'd0;
parameter TX_START  = 3'd1;
parameter TX_BYTE  = 3'd2;
parameter TX_PARITY = 3'd3;
parameter TX_STOP   = 3'd4;
parameter READ_BYTE   = 3'd5;

always @(posedge uart_clk or negedge uart_rst_n) begin
   if (!uart_rst_n) begin
      tstate       <=  IDLE_STATE;
      stx_o_tmp       <=  1'b1;
      counter   <=  5'b0;
      shift_out   <=  7'b0;
      bit_out     <=  1'b0;
      parity_xor  <=  1'b0;
      serial_data_read      <=  1'b0;
      bit_counter <=  3'b0;
   end 
   else if (enable) begin 
      case (tstate)
         IDLE_STATE:begin    
            if (tfifo_empty) begin 
               tstate <=  IDLE_STATE;
               stx_o_tmp <=  1'b1;
            end
            else begin
               serial_data_read <=  1'b0;
               stx_o_tmp  <=  1'b1;
               tstate  <=  READ_BYTE;
            end
         end
         READ_BYTE :    begin
            serial_data_read <=  1'b1;
            case (lcr[1:0])  // number of bits in a word
            2'b00 : begin
                bit_counter <=  3'b100;
                parity_xor  <=  ^tf_data_out[4:0];
            end
            2'b01 : begin
                bit_counter <=  3'b101;
                parity_xor  <=  ^tf_data_out[5:0];
            end
            2'b10 : begin
                bit_counter <=  3'b110;
                parity_xor  <=  ^tf_data_out[6:0];
            end
            2'b11 : begin
                bit_counter <=  3'b111;
                parity_xor  <=  ^tf_data_out[7:0];
            end
            endcase
            {shift_out[6:0], bit_out} <=  tf_data_out;
            tstate <=  TX_START;
         end
         TX_START :    begin
            serial_data_read <=  1'b0;
            if (counter==0) counter <=  5'd15;
            else if (counter == 5'd1) begin
                counter <=  0;
                tstate <=  TX_BYTE;
            end 
            else begin
                counter <=  counter - 1'b1;
            end
            stx_o_tmp <=  1'b0;
         end
         TX_BYTE :    begin
            if (counter==0) counter <=  5'd15;
            else
            if (counter == 5'd1)
            begin
               if (bit_counter > 3'd0) begin
                  bit_counter <=  bit_counter - 1'b1;
                  {shift_out[5:0],bit_out  } <=  {shift_out[6:1], shift_out[0]};
                  tstate <=  TX_BYTE;
               end
               else if (~lcr[3]) begin//parity disabled
                  tstate <=  TX_STOP;
               end
               else begin
                   case ({lcr[4],lcr[5]})
                   2'b00:    bit_out <=  ~parity_xor;//odd parity
                   2'b01:    bit_out <=  1'b1;
                   2'b10:    bit_out <=  parity_xor;//even parity
                   2'b11:    bit_out <=  1'b0;
                   endcase
                   tstate <=  TX_PARITY;
               end
               counter <=  0;
            end
            else
                counter <=  counter - 1'b1;
            stx_o_tmp <=  bit_out; // set output pin
         end
         TX_PARITY :    begin
            if (counter==0)
                counter <=  5'b01111;
            else
            if (counter == 5'b00001)
            begin
                counter <=  4'b0;
                tstate <=  TX_STOP;
            end
            else
                counter <=  counter - 1'b1;
            stx_o_tmp <=  bit_out;
         end
         TX_STOP : begin
            if (counter==0) begin
               //casex ({lcr[2],lcr[1:0]})
               //   3'b0xx:      counter <=  5'b01101;     //13  1 stop bit 
               //   3'b100:      counter <=  5'b10101;     //21 1.5 stop bit
               //   default:      counter <=  5'b11101;     //29 2 stop bits,not surport
               //endcase
               counter <=  5'b11101;     //29 fix 2 stop bits,
            end
            else if (counter == 5'b00001) begin
               counter <=  0;
               tstate <=  IDLE_STATE;
            end
            else begin
               counter <=  counter - 1'b1;
            end

            stx_o_tmp <=  1'b1;
         end
         default : // should never get here
            tstate <=  IDLE_STATE;
      endcase
   end // end if enable
   else
      serial_data_read <=  1'b0;  // serial_data_read must be 1 cycle width
end // transmitter logic

assign serial_out = lcr[6] ? 1'b0 : stx_o_tmp;    // Break condition
assign transmitter_data_out = lcr[6] ? 0 : tf_data_out;    // Break condition
    
endmodule
